<script lang="ts">
import {defineComponent} from "vue";
import Block, {BlockData} from "@/components/minesweeper/Block.vue";
import Top from "@/components/minesweeper/Top.vue";
import {Matrix} from "@/components/comm/matrix";
import {Position, range} from "@/components/comm/utils";

class BlockObj implements BlockData {
  text: string = '';
  pressed: boolean = false;
  boom: boolean = false;
  value: number = 0;
}

export default defineComponent({
  name: "Board",
  components: {Top, Block},
  props: {
    xs: {type: Number, default: 9},  //纵向格数
    ys: {type: Number, default: 9},  //横向格数
    ln: {type: Number, default: 10}, //雷的数量
  },
  data() {
    return {
      top: {
        n: 0,
        rbs: '😊',
      },
      dat: Matrix.from(this.xs, this.ys, () =>
          new BlockObj()
      ),
      running: true,
    };
  },
  mounted() {
    this.create();
  },
  methods: {
    range,
    create() {
      this.top.n = this.ln;
      this.top.rbs = '😊';
      //初始化雷
      for (let n = this.ln; n;) {
        let x = Math.floor(Math.random() * this.xs);
        let y = Math.floor(Math.random() * this.ys);
        if (this.dat.get([x, y]).value !== 9) {
          this.dat.get([x, y]).value = 9;
          n--;
        }
      }
      //初始化数字
      this.dat.forEvery((b, pos) => {
        if (b.value === 9) {
          this.dat.forNear8d(pos, db => {
            if (db.value !== 9) {
              db.value++;
            }
          })
        }
      });
    },
    restart() {
      this.running = true;
      this.dat.forEvery(b => {
        b.text = '';
        b.pressed = false;
        b.boom = false;
        b.value = 0;
      });
      this.create();
    },
    press(pos: Position) {
      if (!this.running) {
        return;
      }
      let obj = this.dat.get(pos);
      if (obj.pressed || obj.text !== '') {
        return;
      }
      this.dat.get(pos).pressed = true;
      if (obj.value === 9) {
        obj.text = '💣'
        obj.boom = true;
        this.top.rbs = "😫";
        //连锁翻开所有雷
        this.dat.forEvery((b, pos) => {
          if (b.value === 9) {
            if (b.text === '🚩') {
              b.text = '✔';
            } else {
              this.press(pos);
            }
          }
        });
        this.running = false;
      } else if (obj.value === 0) {
        //连锁翻开周围方块
        this.dat.forNear8d(pos, (_, dPos) => {
          this.press(dPos);
        });
      } else {
        this.dat.get(pos).text = this.dat.get(pos).value.toString();
      }

      //判断是否胜利
      if (this.running && this.dat.data.flat().every(b => b.value === 9 || b.pressed)) {
        this.running = false;
        this.top.rbs = "😎";
        setTimeout(() => alert('恭喜你赢了！'), 1000);
      }
    },
    mark(pos: Position) {
      if (!this.running) {
        return;
      }
      let obj = this.dat.get(pos);
      if (obj.pressed) {
        return;
      }
      switch (obj.text) {
        case '':
          obj.text = '🚩';
          this.top.n--;
          break;
        case '🚩':
          obj.text = '❓';
          this.top.n++;
          break;
        case '❓':
          obj.text = '';
          break;
      }
    },
  },
})
</script>

<template>
  <div class="main">
    <Top v-model="top" :running="running" :onReStart="restart"/>
    <div class="board">
      <div v-for="x in range(xs)" :key="x">
        <Block v-for="y in range(ys)" :key="`${x} ${y}`"
               v-model="dat.data[x][y]"
               :onLeftClick="()=>press([x, y])"
               :onRightClick="()=>mark([x, y])"
        />
      </div>
    </div>
  </div>
</template>

<style scoped>

</style>